﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Web;
using umbraco.BusinessLogic;

namespace GrailTechnology.OpenCalais
{
    [Serializable]
    public class OpenCalaisService
    {
        #region Private Fields
        private readonly string _licence;
        private List<string> _errors = new List<string>();
        private const string PARAMETERS =
@"&lt;c:params xmlns:c=""http://s.opencalais.com/1/pred/"" xmlns:rdf=""http://www.w3.org/1999/02/22-rdf-syntax-ns#""&gt;&lt;c:processingDirectives c:allowDistribution=""true"" c:enableMetaDataType=""GenericRelations,SocialTags"" c:allowSearch=""true"" c:contentType=""text/txt"" c:outputFormat=""Text/Simple""&gt;&lt;/c:processingDirectives&gt;&lt;c:externalMetadata&gt;&lt;/c:externalMetadata&gt;&lt;/c:params&gt;";

        #endregion

        public OpenCalaisService()
        {
            _licence = Utils.GetLicence;
            if (string.IsNullOrEmpty(_licence))
            {
                Log.Add(LogTypes.Error, int.Parse(HttpContext.Current.Request["id"]), "AutoTags - AutoTags.APIKey not found in web.config");
                _errors.Add("Missing API key. Add your OpenCalais licence key to the appSettings section in web.config, with a key: AutoTags.APIKey");
            }
            bool proxyError;
            Proxy = Utils.GetProxy(out proxyError);
            if (proxyError)
            {
                Log.Add(LogTypes.Error, int.Parse(HttpContext.Current.Request["id"]), "AutoTags - Proxy details incomplete");
                _errors.Add("Proxy details incomplete. You haven't specified the correct number of proxy items (username, password and domain");
            }
        }

        // Debug/Test Ctor
        public OpenCalaisService(string licence)
        {
            _licence = licence;
            Proxy = null;
        }

        #region Properties

        private WebProxy Proxy
        {
            get;
            set;
        }

        public bool ContainsErrors
        {
            get { return Errors.Count > 0 ? true : false; }
        }

        public List<string> Errors
        {
            get { return _errors; }
        }

        public List<string> Tags
        {
            get;
            set;
        }

        public string Content
        {
            get;
            set;
        }

        private string Response
        {
            get;
            set;
        }

        #endregion

        public void GenerateTags(string content)
        {
            if (!ContainsErrors)
            {
                Content = content;
                if (Request())
                {
                    Tags = GetTags();
                }
            }
        }

        public List<string> GetTags()
        {
            var tags = new List<string>();
            if (!string.IsNullOrEmpty(Response))
            {
                tags = Utils.ResponseToList(Response);
            }

            if (tags.Count == 0)
            {
                _errors.Add("No tags were found for this content");
            }
            return tags;
        }

        private bool Request()
        {
            bool success;
            Response = ProccessText("http://api.opencalais.com/enlighten/calais.asmx/Enlighten", "application/x-www-form-urlencoded", out success);
            return success;
        }

        /// <summary>
        /// This function send an manual request to Calais API
        /// </summary>
        /// <param name="uri">API location</param>
        /// <param name="contentType">content type (see at http://www.opencalais.com/APIcalls) </param>
        /// <param name="success">whether the request has been successful</param>
        /// <returns>response or error</returns>
        private string ProccessText(string uri, string contentType, out bool success)
        {
            success = false;

            if (string.IsNullOrEmpty(Content))
            {
                _errors.Add("There is no content to analyse");
                return string.Empty;
            }

            try
            {
                var client = new WebClient();

                client.Headers.Add("Content-Type", contentType);

                string sendParams = CreatePostParams();

                if (Proxy != null)
                {
                    client.Proxy = Proxy; // some might need it ...
                }

                byte[] byteArray = Utils.PostToByteArray(sendParams);
                //send the data to uri using post methode
                byte[] responseArray = client.UploadData(uri, "POST", byteArray);

                _errors.Clear();
                success = true;
                return Utils.ByteArrayToString(responseArray);
            }
            catch (Exception ex)
            {
                Log.Add(LogTypes.Error, int.Parse(HttpContext.Current.Request["id"]), string.Format("AutoTags - Unable to connect to OpenCalais service at this time"));
                _errors.Add("There was an error contacting the service - " + ex.Message);
                return string.Empty;
            }
        }

        /// <summary>
        /// Create POST params
        /// </summary>
        /// <returns>Post params as string</returns>
        private string CreatePostParams()
        {
            //see the url and html endcoding...
            var sendParams = string.Format("licenseID={0}&content={1}&paramsXML={2}", _licence,
                                       HttpUtility.UrlEncode(Content), HttpUtility.HtmlDecode(PARAMETERS));

            return sendParams;
        }
    }
}